#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     __init__.py
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/7/28
-------------------------------------------------
   修改描述-2021/7/28:         
-------------------------------------------------
"""
import redis
import json
from fastapi import FastAPI
from apps.config.redis_conf import redisconf
class Struct(dict):
    """
    为字典加上点语法. 例如:
    >>> o = Struct({'a':1})
    >>> o.a
    >>> 1
    >>> o.b
    >>> None
    """

    def __init__(self, *e, **f):
        if e:
            self.update(e[0])
        if f:
            self.update(f)

    def __getattr__(self, name):
        # Pickle is trying to get state from your object, and dict doesn't implement it.
        # Your __getattr__ is being called with "__getstate__" to find that magic method,
        # and returning None instead of raising AttributeError as it should.
        if name.startswith('__'):
            raise AttributeError
        return self.get(name)

    def __setattr__(self, name, val):
        self[name] = val

    def __delattr__(self, name):
        self.pop(name, None)

    def __hash__(self):
        return id(self)


class SyncRedisClient:
    # def __init__(self, name, prefix='', **Cache):
    #     self.pool = redis.ConnectionPool(**Cache)
    #     self.sync_redis = redis.Redis(connection_pool=self.pool)
    #     self.prefix = prefix
    #     self.timeout = 0

    def __init__(self, app: FastAPI = None):
        # 如果有APPC传入则直接的进行初始化的操作即可
        self.sync_redis = None
        if app is not None:
            self.init_app(app)

    def init_app(self, app: FastAPI):
        self.app = app

        @app.on_event("startup")
        def startup_event():
            app.state.sync_redis = self.init_sync_redis_pool()

            # app.state.sync_redis.set("ssss",'sssssssssssss')
            # # 初始化缓冲器对象
            # from apps.ext.cache import FastAPICache
            # from apps.ext.cache.backends.redis import RedisBackend
            # FastAPICache.init(RedisBackend(self.redis_db), prefix="zhongyin-cache")


        @app.on_event("shutdown")
        def shutdown_event():
            app.state.redis.close()
            app.state.redis.wait_closed()

    def init_config(self):
        self.init_sync_redis_pool()

    def init_sync_redis_pool(self):
        self.pool = redis.ConnectionPool(host=redisconf.HOST,port=redisconf.PORT,password=redisconf.PASSWORD,max_connections=512)
        self.sync_redis = redis.Redis(connection_pool=self.pool)
        self.prefix = ''
        self.timeout = 0
        return self.sync_redis


    #######################
    def get(self, key):
        # redis get 操作
        if not isinstance(key, str):
            print("TypeError: Redis get key must be str")
            return ""
        data = self.sync_redis.get(self.prefix + key)
        if not data:
            return ""
        # redis中获取出来的都是bytes类型数据，需要转换成str
        return data.decode("utf-8")

    def set(self, key, value,ex=None):
        # redis set 操作
        if not isinstance(key, str):
            print("TypeError: Redis get key must be str")
            return False
        if isinstance(value, list) or isinstance(value, dict):
            value = json.dumps(value)
        if not ex:
            data = self.sync_redis.set(self.prefix + key, value)
        else:
            data = self.sync_redis.set(self.prefix + key, value,ex=ex)
        return data

    def exists(self, key):
        # redis 判断 key 是否存在
        if not isinstance(key, str):
            print("TypeError: Redis get key must be str")
            return False
        return self.sync_redis.exists(self.prefix + key)

    def delete(self, key):
        # redis 删除key
        if not isinstance(key, str):
            print("TypeError: Redis get key must be str")
            return False
        return self.sync_redis.delete(self.prefix + key)

    def mset(self, *args, **kwargs):
        # redis mset 操作（批量设置值）
        data = {}
        for d in args:
            if not isinstance(d, dict):
                print("TypeError: Redis mset key must be dict")
                return False
            data.update(d)
        data.update(kwargs)
        if not data:
            return False
        final_data = {}
        for d in data:
            final_data[self.prefix + d] = data[d]
        flag = self.sync_redis.mset(final_data)
        return flag

    def mget(self, keys):
        # redis mget 操作（批量获取值）
        data = []
        if not isinstance(keys, (list, tuple)):
            print("TypeError: Redis mget key must be list or tuple")
            return False
        for d in keys:
            data.append(self.prefix + d)
        data = self.sync_redis.mget(data)
        data = [d.decode("utf-8") for d in data]
        return data

    def incr(self, key, amount=1):
        # 自增amount个
        if not isinstance(key, str):
            print("TypeError: Redis incr key must be str")
            return False
        key = self.prefix + key
        return self.sync_redis.incr(key, amount)

    def decr(self, key, amount=1):
        # 自减amount个
        if not isinstance(key, str):
            print("TypeError: Redis decr key must be str")
            return False
        key = self.prefix + key
        return self.sync_redis.decr(key, amount)

    def hset(self, key, value):
        # redis hash set 操作
        if not isinstance(key, str):
            print("TypeError: Redis hset key must be str")
            return False
        return self.sync_redis.hset(self.prefix, key, value)

    def hget(self, key):
        # redis hash get 操作
        if not isinstance(key, str):
            print("TypeError: Redis hset key must be str")
            return False
        data = self.sync_redis.hget(self.prefix, key)
        return data.decode("utf-8")

    def hmset(self, *args, **kwargs):
        # redis mset 操作（批量设置值）
        data = {}
        for d in args:
            if not isinstance(d, dict):
                print("TypeError: Redis mset key must be dict")
                return False
            data.update(d)
        data.update(kwargs)
        if not data:
            return False
        flag = self.sync_redis.hmset(self.prefix, data)
        return flag

    def zadd(self, *args, **kwargs):
        # redis zadd操作(批量设置值至args有序集合中)
        if not (args or kwargs):
            return False

        self.sync_redis.zadd(self.prefix, *args, **kwargs)

    def zrem(self, name):
        # redis zrem操作(删除name有序集合中的特定元素)
        if not name:
            return False
        flag = self.sync_redis.zrem(self.prefix, name)
        return flag

    def zincrby(self, name, value, amount=1):
        # 如果在key为name的zset中已经存在元素value，则该元素的score增加amount，否则向该集合中添加该元素，其score的值为amount
        if not (name or value):
            return False
        return self.sync_redis.zincrby(self.prefix, value, amount)

    def zrevrank(self, value):
        if not value:
            return False
        return self.sync_redis.zrevrank(self.prefix, value)

    def zscore(self, member):
        if not member:
            return False
        return self.sync_redis.zscore(self.prefix, member)

    def zrange(self, start, end, withscores=False, desc=False):
        return self.decoding(self.sync_redis.zrange(self.prefix, start, end, withscores=withscores, desc=desc))

    def decoding(self, o):
        if not isinstance(o, str):
            return o
        data = json.loads(o)
        return self.decode(data)

    def decode(self, data):
        if isinstance(data, dict):
            return Struct(data)
        elif isinstance(data, (list, tuple)):
            return [self.decode(d) for d in data]
        return data



sync_redis_client = SyncRedisClient()